﻿using System;
using System.Collections.Generic;
using System.Text;

namespace OliveChess
{

    public struct Move : IComparable
    //class Move
    {
   
	    public int from;
	    public int to;

        public Piece piece;  // moved piece
        public Piece cPiece; // captured piece

        public int color;
        public int cColor;

        public char promotion;
        
        public Move(int square1, int square2, Position p)
        {
            from = square1;
            to = square2;
            piece = p.GetPiece(square1);
            cPiece = p.GetPiece(square2);
            this.promotion = '0';
            color = GetColor(piece);
            cColor = GetColor(cPiece);
        }
        
	    public Move(int square1, int square2, Position p, char promotion) {
		    from = square1;
		    to = square2;
            piece = p.GetPiece(square1);
            cPiece = p.GetPiece(square2);
	        this.promotion = promotion;
            color = GetColor(piece);
            cColor = GetColor(cPiece);
	    }
	
	    public Move(Move move) {
		    this.from = move.from;
		    this.to = move.to;
            piece = move.piece;
            cPiece = move.cPiece;
	        this.promotion = move.promotion;
            color = GetColor(piece);
            cColor = GetColor(cPiece);
	    }

        public Move(String move, Position p)
        {
            this.from = Square.Get(move.Substring(0, 2));
            this.to = Square.Get(move.Substring(2, 2));
            piece = p.GetPiece(from);
            cPiece = p.GetPiece(to);
            if (move.Length == 5)
            {
                promotion = move[4];
            }
            else
            {
                promotion = '0';
            }
            color = GetColor(piece);
            cColor = GetColor(cPiece);
        }

        private static int GetColor(Piece piece)
        {
            if ((piece == Piece.W_PAWN)
                || (piece == Piece.W_BISHOP)
                || (piece == Piece.W_KNIGHT)
                || (piece == Piece.W_ROOK)
                || (piece == Piece.W_QUEEN)
                || (piece == Piece.W_KING)) return 0;
            return 1;
        }

	    public bool IsEqual(Move m) {
		    return ( (m.from == from) && (m.to == to) && (m.promotion == promotion));
	    }


        override public bool Equals(Object obj)
        {
            return this.IsEqual((Move)obj);
        }

        //public static Move Null = new Move(128,128,'0');
        	
	    public override String ToString() {
            if (promotion != '0') return Square.ToString(from) + Square.ToString(to) + promotion; 
            return Square.ToString(from) + Square.ToString(to); 
	    }

        // display the moved piece and indicates when a piece is captured
        // useful for debug
        public String ToFullAlgebric()
        {
            String sfrom = Square.ToString(from);
            String sto = Square.ToString(to);

            char spiece = ToChar(piece);
            char separator = (cPiece != Piece.NO_PIECE) ? 'x' : '-'; 

            if (promotion != '0') return spiece + sfrom + separator + sto + promotion;
            return spiece + sfrom + separator + sto;
        }

        private char ToChar(Piece piece)
        {
            switch (piece)
            {
                case Piece.W_KING:
                case Piece.B_KING:
                    return 'K';
                case Piece.W_QUEEN:
                case Piece.B_QUEEN:
                    return 'Q';
                case Piece.W_KNIGHT:
                case Piece.B_KNIGHT:
                    return 'N';
                case Piece.W_BISHOP:
                case Piece.B_BISHOP:
                    return 'B';
                case Piece.W_ROOK:
                case Piece.B_ROOK:
                    return 'R';
                case Piece.W_PAWN:
                case Piece.B_PAWN:
                    return 'P';
            default:

                    return '0';
            }
        }

        public override int GetHashCode()
        {
            return (from)+65*(to)+65*65*(promotion);
        }

        public static bool operator==(Move m1, Move m2){
            return (m1.from==m2.from) && (m1.to==m2.to) && (m1.promotion==m2.promotion);
        }

        public static bool operator!=(Move m1, Move m2)
        {
            return (m1.from != m2.from) || (m1.to != m2.to) || (m1.promotion != m2.promotion);
        }

        // Comparer used to do a preliminary sort of lists of legalMoves
        public int CompareTo(object obj)
        {
            // Rules:
            // 1 - captures first, then escape moves (king?), then quiet moves
            // 2 - agressive chessmen first, pawns last (except for last ranks?)

            int val = evalMoveBruitality(this);
            int valo = evalMoveBruitality((Move)obj);

            return valo - val;
        }

        private int evalMoveBruitality(Move move)
        {
            // best captures first
            int captureEval = 2000*GetVal(move.cPiece);
            // lowest piece moved for capture first
            int pieceEval = 2000-GetVal(move.piece);
            return captureEval + pieceEval;
        }

        private int GetVal(Piece piece)
        {
            switch (piece)
            {
                case Piece.W_KING:
                case Piece.B_KING:
                    return 1900;
                case Piece.W_QUEEN:
                case Piece.B_QUEEN:
                    return 900;
                case Piece.W_ROOK:
                case Piece.B_ROOK:
                    return 500;
                case Piece.W_BISHOP:
                case Piece.B_BISHOP:
                    return 300;
                case Piece.W_KNIGHT:
                case Piece.B_KNIGHT:
                    return 300;
                case Piece.W_PAWN:
                case Piece.B_PAWN:
                    return 90;
                case Piece.NO_PIECE:
                default:
                    return 0;
            }
        }

        internal bool IsCapture()
        {
            return (this.cPiece != Piece.NO_PIECE);
        }
    }

}
